/*
	FileMaker
	
	This class takes FileBlueprint objects, and creates them.
	
	It first makes sure the Command class is created last,
	it then loads the template files,
	pares them to have their tags replaced with class values,
	and finally writes them out as ActionScript files in the
	developer's project package structure via JSFL.
	
	This class assumes it'll get the jsfl function passed
	to it by it's parent.
	
    Created by Jesse R. Warden a.k.a. "JesterXL"
	jesterxl@jessewarden.com
	http://www.jessewarden.com
	
	This is release under a Creative Commons license. 
    More information can be found here:
    
    http://creativecommons.org/licenses/by/2.5/
*/

package
{
	import FileBlueprint;
	import flash.events.Event;
	import flash.system.Capabilities;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	public class FileMaker
	{
		private static var inst:FileMaker;
		
		public static function getInstance():FileMaker
		{
			if(inst == null) inst = new FileMaker();
			return inst;	
		}
		
		protected var scope:Object;
		protected var jsflFunction:Function;
		protected var fileList:Array;
		protected var doneCallback:Function;
		protected var currentFileBlueprint:FileBlueprint;
		
		protected var eventClass:String = "";
		protected var delegateClass:String = "";
		protected var callbackClass:String = "";
		
		protected var createdFiles_array:Array;
		
		public function FileMaker()
		{
		}
		
		public function buildFiles(p_scope:Object, 
									p_jsflFunc:Function,
									p_fileList:Array,
									p_doneFunc:Function):void
		{
			scope			= p_scope;
			jsflFunction	= p_jsflFunc;
			fileList		= p_fileList;
			doneCallback	= p_doneFunc;
			
			createdFiles_array = [];
			
			// need to sort the file list; we only process commands last
			var commandSortFunc:Function = function(a:FileBlueprint, b:FileBlueprint):Number
			{
				if(a.isCommand)
				{
					return 1;
				}
				else if(b.isCommand)
				{
					return -1;
				}
				else
				{
					return 0;
				}
			};
			//DebugWindow.debugHeader();
			//DebugWindow.debug("sort before: " + fileList);
			fileList.sort(commandSortFunc);
			//DebugWindow.debug("sort after: " + fileList);
			
			startBuilding();
		}
		
		protected function jsfl(p_str:String):String
		{
			var result:String = jsflFunction.call(scope, p_str);
			return result;
		}
		
		protected function startBuilding():void
		{
			if(currentFileBlueprint == null)
			{
				if(fileList.length > 0)
				{
					currentFileBlueprint = fileList.shift();
					buildNextMofo();
				}
				else
				{
					doneCallback.call(scope, createdFiles_array);
				}
			}
		}
		
		/*
		protected function buildNextMofo():void
		{
			// first, build the class string
			var newline:String;
			
			if(flash.system.Capabilities.os.indexOf("indows") != -1)
			{
				newline ="\\r\\n";
			}
			else if(flash.system.Capabilities.os == "Mac OS")
			{
				newline ="\\n";
			}
			else if(flash.system.Capabilities.os.indexOf("inux") != -1)
			{
				newline ="\\n";
			}
			
			//linebreak = "\"\\n\"";
			
			var hasABaseClass:Boolean = false;
			if(currentFileBlueprint.baseClass != null && currentFileBlueprint.baseClass != "")
			{
				hasABaseClass = true;	
			}
		
			var str:String = "";
			if(hasABaseClass == true)
			{
				str += "import " + currentFileBlueprint.baseClass + ";" + newline;
				str += newline;
			}
			str += "class " + currentFileBlueprint.packagePrefix;
			str += "." + currentFileBlueprint.fileName + " ";
			
			if(hasABaseClass == true)
			{
				var baseClassPackageArray:Array = currentFileBlueprint.baseClass.split(".");
				str += "extends " + baseClassPackageArray[baseClassPackageArray.length - 1];
			}
			str += newline;
			str += "{" + newline;
			str += newline;
			
			if(currentFileBlueprint.isEvent == true)
			{
				str += "\tpublic static var " + currentFileBlueprint.useCase.toUpperCase();
				str += ":String";
				str += " = \"" + currentFileBlueprint.useCase + "\";" + newline;
				str += newline + newline;
			}
			
			str += "\tpublic function " + currentFileBlueprint.fileName + "()" + newline;
			str += "\t{" + newline;
			str += "\t}" + newline;
			str += newline;
			str += "}";
			
			// second, write it
			// FLfile.write(fileURI, textToWrite, [ , strAppendMode])
			var fileURI:String = currentFileBlueprint.filePath + "/" + currentFileBlueprint.fileName + currentFileBlueprint.fileExtension;
			//var writeResult:String = jsfl('FLfile.write("' + fileURI + '", "test");');
			
			var cmd:String = "FLfile.write(";
			cmd += "'" + fileURI + "'";
			cmd += ", ";
			cmd += "'" + str + "'";
			cmd += ");";
			var writeResult:String = jsfl(cmd);
			DebugWindow.debugHeader();
			DebugWindow.debug("writeResult: " + writeResult);
			
			currentFileBlueprint = null;
			// third, build again
			startBuilding();
		}
		*/
		
		protected function buildNextMofo():void
		{
			// first, load the template
			var req:URLRequest = new URLRequest(currentFileBlueprint.templateFile);
			var loader:URLLoader = new URLLoader(req);
			loader.addEventListener(Event.COMPLETE, onTemplateLoaded);
		}
		
		protected function onTemplateLoaded(event:Event):void
		{
			// second, inject goodness into the template string
			var str:String = URLLoader(event.target).data as String;
			var latestClass:String = currentFileBlueprint.packagePrefix + "." + currentFileBlueprint.fileName;
			var baseClassArray:Array = currentFileBlueprint.baseClass.split(".");
			var baseClassName:String;
			if(baseClassArray.length > 1)
			{
				baseClassName = baseClassArray[baseClassArray.length - 1];
			}
			else
			{
				baseClassName = callbackClass;
			}
			
			// TODO: Need to while loop the custom tags just in case there is more than one
			if(currentFileBlueprint.isEvent == true)
			{
				eventClass = latestClass;
				str = globalReplace(str, "<$BaseClass$>", currentFileBlueprint.baseClass);
				str = globalReplace(str, "<$BaseClassName$>", baseClassName);
				str = globalReplace(str, "<$PackagePrefix$>", currentFileBlueprint.packagePrefix);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
				str = globalReplace(str, "<$UseCaseToUpperCase$>", currentFileBlueprint.useCase.toUpperCase());
				str = globalReplace(str, "<$UseCase$>", currentFileBlueprint.useCase);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
			}
			
			if(currentFileBlueprint.isDelegate == true)
			{
				delegateClass = latestClass;
				str = globalReplace(str, "<$BaseClass$>", currentFileBlueprint.baseClass);
				str = globalReplace(str, "<$BaseClassName$>", baseClassName);
				str = globalReplace(str, "<$PackagePrefix$>", currentFileBlueprint.packagePrefix);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
			}
			
			if(currentFileBlueprint.isCallback == true)
			{
				callbackClass = latestClass;
				str = globalReplace(str, "<$BaseClass$>", currentFileBlueprint.baseClass);
				str = globalReplace(str, "<$BaseClassName$>", baseClassName);
				str = globalReplace(str, "<$PackagePrefix$>", currentFileBlueprint.packagePrefix);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
			}
			
			if(currentFileBlueprint.isCommand == true)
			{
				//DebugWindow.debug("currentFileBlueprint.isCommand is true");
				//DebugWindow.debug("eventClass: " + eventClass);
				var eventClassArray:Array = eventClass.split(".");
				//DebugWindow.debug("eventClassArray: " + eventClassArray);
				var eventClassName:String;
				//DebugWindow.debug("eventClassName: " + eventClassName);
				if(eventClassArray.length > 1)
				{
					eventClassName = eventClassArray[eventClassArray.length - 1];
				}
				else
				{
					eventClassName = eventClass;
				}
				//DebugWindow.debug("eventClassName: " + eventClassName);
				str = globalReplace(str, "<$BaseClass$>", currentFileBlueprint.baseClass);
				str = globalReplace(str, "<$BaseClassName$>", baseClassName);
				str = globalReplace(str, "<$PackagePrefix$>", currentFileBlueprint.packagePrefix);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
				str = globalReplace(str, "<$ClassName$>", currentFileBlueprint.fileName);
				str = globalReplace(str, "<$EventClass$>", eventClass);
				str = globalReplace(str, "<$EventClassName$>", eventClassName);
				str = globalReplace(str, "<$DelegateClass$>", delegateClass);
				var callbackClassArray:Array = callbackClass.split(".");
				//DebugWindow.debug("callbackClassArray: " + callbackClassArray);
				var callbackClassName:String;
				if(callbackClassArray.length > 1)
				{
					callbackClassName = callbackClassArray[callbackClassArray.length - 1];
				}
				else
				{
					callbackClassName = callbackClass;
				}
				//DebugWindow.debug("callbackClassName: " + callbackClassName);
				str = globalReplace(str, "<$CallbackClass$>", callbackClass);
				str = globalReplace(str, "<$CallbackClassName$>", callbackClassName);
			}
			
			// clean up the linebreaks so JSFL doesn't get ticked off
			str = globalReplace(str, "\r\n", "\\r\\n");
			
			// third, write the mug
			var fileURI:String = currentFileBlueprint.filePath + "/" + currentFileBlueprint.fileName + currentFileBlueprint.fileExtension;
			var cmd:String = "FLfile.write(";
			cmd += "'" + fileURI + "'";
			cmd += ", ";
			cmd += "'" + str + "'";
			cmd += ");";
			var writeResult:String = jsfl(cmd);
			// if it's "false", it failed... usually an error string though
			//DebugWindow.debugHeader();
			//DebugWindow.debug("writeResult: " + writeResult);
			
			if(writeResult == "true") createdFiles_array.push(currentFileBlueprint.fileName);
			
			// fourth?  We done!
			currentFileBlueprint = null;
			// Build again...
			startBuilding();
		}
		
		// NOTE: does not work with regular expressions
		public function globalReplace(p_source:String, p_pattern:String, p_replacement:String):String
		{
			while(p_source.indexOf(p_pattern) > -1)
			{
				p_source = p_source.replace(p_pattern, p_replacement);
			}
			return p_source;
		}
		
	}
}